home *** CD-ROM | disk | FTP | other *** search
- Subject: v15i008: ASCII to PostScript filter
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Barry Brachman <grads.cs.ubc.ca!brachman>
- Posting-number: Volume 15, Issue 8
- Archive-name: lwf
-
- [ Features include multi-column, portrait, and indented output.
- Think of this as a "pr" for a PostScript machine. I love the
- spelling of the prolog file... I repacked things. --r$ ]
-
- Enclosed is lwf, an ASCII to PostScript filter, as recently advertised
- in comp.lang.postscript/info-postscript. The name stands for
- LaserWriter Filter.
-
- This program
- Barry Brachman | {ihnp4!alberta,uw-beaver,uunet}!
- Dept. of Computer Science| ubc-vision!ubc-csgrads!brachman
- Univ. of British Columbia| brachman@grads.cs.ubc.cdn
- Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa
- (604) 228-4327 | brachman@ubc.csnet
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: Makefile README lwf.c lwf.man prologue range.c
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(1002 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X
- CFLAGS = -O
- X
- X# Where to put lwf
- LWF = /usr/local/lwf
- X
- X# Where to put the man page
- MAN = /usr/man/manl/lwf.l
- X
- X# Where to put the PostScript prologue file
- PROLOGUE = /usr/local/lib/lwf.prologue
- X
- X# Environment options:
- X#
- X# -DPR=\"where pr is if not /bin/pr\"
- X# -DSYSV For System V (assumes SYSV-style pr)
- X# -DREVERSE=0 Set to non-zero if page reversal is to be the default
- X# -DHOSTNAME=\"yourhostname\" If you don't have the hostname() system call
- ENV = -DPROLOGUE=\"$(PROLOGUE)\" -DREVERSE=0
- X
- lwf: lwf.o range.o
- X cc -s -o lwf lwf.o range.o -lm
- X
- lwf.o: lwf.c
- X cc $(CFLAGS) -c $(ENV) lwf.c
- X
- range.o: range.c
- X cc $(CFLAGS) -c range.c
- X
- X# Create the program to demonstrate and debug the range checking routine
- range: range.c
- X cc $(CFLAGS) -DRANGE_DEBUG -o range range.c
- X
- install: lwf lwf.man
- X cp prologue $(PROLOGUE)
- X chmod 0644 $(PROLOGUE)
- X cp lwf $(LWF)
- X chmod 0755 $(LWF)
- X ls -l $(LWF)
- X cp lwf.man $(MAN)
- X rm -f lwf lwf.o range.o
- X
- lint:
- X lint -abchx $(ENV) lwf.c
- X
- clean:
- X rm -f core lwf lwf.o range.o
- X
- END_OF_FILE
- if test 1002 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(1619 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X
- Lwf converts ASCII text files to PostScript.
- It has been tested on the Apple LaserWriter/LaserWriter+ and the NEC
- Silentwriter LC-890. Most of the processing is done on the host
- rather than on the printer. The name "lwf", perhaps poorly chosen, stands
- for "LaserWriter Filter".
- X
- There may be a couple of minor Berkeley-isms in the program (see the
- routine setup()) and it is somewhat Unix dependent (eg., popen(), /bin/pr
- are expected). The output conforms to the Adobe 2.0 file structuring
- conventions. The program is set up to use the (fixed-width) Courier font.
- If you use another font you'll have to modify the mapping table in lwf.c.
- I can't recommend a proportional font for this purpose.
- X
- The distribution includes the following files:
- X
- README This file
- Makefile
- lwf.c LaserWriter filter to convert ASCII text to PostScript
- range.c Routine to check if a number is in a given range
- lwf.man Manual page for lwf
- prologue Default PostScript support file
- X
- Please check the Makefile and the configurable #defines in lwf.c.
- Check if the man page needs to be revised for your environment.
- You can then proceed with 'make install'.
- X
- If you come across any bugs, including nonconformance to Adobe 2.0, or
- make any changes you'd like to share please send mail to me rather than
- posting to the net.
- X
- Enjoy.
- X
- X-----
- Barry Brachman | {ihnp4!alberta,uw-beaver,uunet}!
- Dept. of Computer Science| ubc-vision!ubc-csgrads!brachman
- Univ. of British Columbia| brachman@grads.cs.ubc.cdn
- Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa
- X(604) 228-4327 | brachman@ubc.csnet
- X
- END_OF_FILE
- if test 1619 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'lwf.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lwf.c'\"
- else
- echo shar: Extracting \"'lwf.c'\" \(26651 characters\)
- sed "s/^X//" >'lwf.c' <<'END_OF_FILE'
- X
- X/* vi: set tabstop=4 : */
- X
- X/*
- X * lwf - Convert ASCII text to PostScript
- X *
- X * Usage:
- X * lwf [-d] [-i#] [-l] [-m] [-olist] [-p[str]] [-P filename] [-s#] [-t#]
- X * [-v] [file ...]
- X *
- X * Options:
- X * -d Debug mode
- X * -i# Indent each line # inches (so much for metric)
- X * -l Landscape instead of Portrait
- X * -m Use 3 hole punch margins
- X * -olist Only print pages in the specified range
- X * -p[str] Use pr to print, passing optional string
- X * -P filename Copy prologue from filename instead of default
- X * -r Toggle page reversal flag (see Makefile)
- X * -s# Use point size #
- X * -t# Spaces between tab stops is # characters
- X * -v Verbose
- X * -S Standalone mode (print header page, use EOF's)
- X *
- X * If no files are specified, stdin is used.
- X * Form feeds handled
- X * Backspacing with underlining (or overprinting) works
- X * The output conforms to Adobe 2.0
- X *
- X * Problems:
- X * - assumes fixed-width (non-proportional) font in some places
- X * - can't back up (using backspaces) over tabs
- X * - assumes 8.5 x 11.0 paper
- X *
- X * BJB - Jun/87
- X * ========================================================================
- X *
- X * Permission is given to freely copy and distribute this software provided:
- X *
- X * 1) You do not sell it,
- X * 2) You do not use it for commercial advantage, and
- X * 3) This notice accompanies the distribution
- X *
- X * Copyright (c) 1988
- X * Barry Brachman
- X * Dept. of Computer Science
- X * Univ. of British Columbia
- X * Vancouver, B.C. V6T 1W5
- X *
- X * .. {ihnp4!alberta, uw-beaver, uunet}!ubc-vision!ubc-csgrads!brachman
- X * brachman@grads.cs.ubc.cdn
- X * brachman%ubc.csnet@csnet-relay.arpa
- X * brachman@ubc.csnet
- X * ========================================================================
- X */
- X
- X#include <sys/file.h>
- X#include <ctype.h>
- X#include <pwd.h>
- X#include <stdio.h>
- X
- X#define min(a, b) ((a) < (b) ? (a) : (b))
- X
- X/*
- X * Configurable...
- X * BUFOUT should be fairly large
- X */
- X#define BUFIN 1024 /* maximum length of an input line */
- X#define BUFOUT (BUFIN * 5)
- X#define MAXPAGES 10000 /* maximum number of pages per job */
- X#define DEFAULT_TAB_SIZE 8
- X#define DEFAULT_POINT_SIZE 10
- X#ifndef PROLOGUE
- X#define PROLOGUE "/usr/local/lib/lwf.prologue"
- X#endif
- X#ifndef REVERSE
- X#define REVERSE 0
- X#endif
- X#ifndef PR
- X#define PR "/bin/pr"
- X#endif
- X
- X#ifdef SYSV
- X#define rindex strrchr
- X#endif
- X
- X/*
- X * As mentioned in the man page, /bin/pr doesn't handle formfeeds correctly
- X * when doing multicolumn formatting
- X * Instead of starting a new column or page it passes a formfeed through,
- X * causing pr and lwf to get out-of-synch with regard to the current
- X * location on the page
- X * If your pr behaves this way (4.[23] does, SYSV doesn't), define PRBUG so
- X * that fgetline() will filter out these bogus formfeeds while preserving
- X * the column structuring
- X */
- X#ifndef SYSV
- X#define PRBUG 1
- X#endif
- X
- X/*
- X * PostScript command strings defined in the prologue file
- X */
- X#define BACKSPACE "B"
- X#define ENDPAGE "EP"
- X#define LINETO "L"
- X#define MOVETO "M"
- X#define NEWPATH "NP"
- X#define SHOW "S"
- X#define STARTPAGE "SP"
- X#define STARTHPAGE "SHP"
- X#define STARTLPAGE "SLP"
- X#define STROKE "ST"
- X#define TAB "T"
- X
- X/*
- X * Conformance requires that no PostScript line exceed 256 characters
- X */
- X#define MAX_OUTPUT_LINE_LENGTH 256
- X
- X#define TEXTFONT "Courier"
- X#define HEADERFONT "Times-Roman"
- X#define HEADERPS 18 /* header page point size */
- X
- X#define PORTRAIT_START_Y 768 /* first row (Y coord) on each page */
- X#define LANDSCAPE_START_Y 576
- X#define START_X 25 /* position of start of each line */
- X#define START_Y_HEADER 700 /* first row (Y coord) of header */
- X#define THREE_HOLE_X 1.0 /* portrait x offset (inches) 3 hole */
- X#define THREE_HOLE_Y 0.5 /* landscape y offset (inches) 3 hole */
- X
- X#define MAX_X 612
- X#define MAX_Y 792
- X
- X#define SEP_CHAR '\001' /* pr column separator character */
- X
- X#define PS_EOF 04
- X
- X#define NPSIZES 6
- struct psize {
- X int size; /* point size */
- X double charsperinch; /* approx. char width, for Courier */
- X int portrait_page_length; /* page length in lines */
- X int portrait_cols; /* maximum # of chars per line */
- X int landscape_page_length;
- X int landscape_cols;
- X} psize[NPSIZES] = {
- X 7, 17.0, 108, 135, 80, 181,
- X 8, 15.0, 94, 118, 70, 159,
- X 9, 14.0, 84, 105, 62, 141,
- X 10, 12.0, 75, 94, 56, 127,
- X 11, 11.0, 68, 86, 51, 115,
- X 12, 10.0, 62, 79, 46, 106
- X};
- X
- X#define USAGE \
- X"[-d] [-i#] [-l] [-m] [-olist] [-p[str]] [-r] [-s#] [-t#] [-v] [-S] [file ...]"
- X
- long page_map[MAXPAGES]; /* offset of first byte of each page */
- int page_count;
- X
- int lines_per_page;
- int columns;
- int point_size;
- int start_x, start_y;
- int ncopies;
- X
- char bufin[BUFIN]; /* input buffer */
- char bufout[BUFOUT]; /* used for page reversal and output buffering */
- X
- char *currentdate, *username;
- char hostname[32];
- X
- int row;
- char *range;
- int tabstop;
- char *propts;
- X
- int dflag, lflag, mflag, pflag, rflag, vflag, Sflag;
- X
- char *strcpy();
- char *fgetline();
- char *sprintf();
- X
- char *prologue;
- char *progname;
- X
- char *version = "lwf V2.0 brachman@ubc.csnet 21-Feb-88";
- X
- main(argc, argv)
- int argc;
- char **argv;
- X{
- X register int i, j, first_file;
- X char *pc;
- X struct psize *p, *get_psize();
- X double offset, atof();
- X char *rindex();
- X FILE *infile, *popen();
- X double ceil();
- X
- X if ((pc = rindex(argv[0], '/')) != (char *) NULL)
- X progname = pc + 1;
- X else
- X progname = argv[0];
- X range = ":";
- X propts = "";
- X tabstop = DEFAULT_TAB_SIZE;
- X page_count = 0;
- X ncopies = 1;
- X offset = 0.0;
- X prologue = PROLOGUE;
- X p = get_psize(DEFAULT_POINT_SIZE);
- X rflag = REVERSE;
- X
- X for (i = 1; i < argc && argv[i][0] == '-'; i++) {
- X switch (argv[i][1]) {
- X case 'c':
- X ncopies = atof(&argv[i][2]);
- X if (ncopies <= 0) {
- X fatal("number of copies must be > 0");
- X /*NOTREACHED*/
- X }
- X break;
- X case 'd':
- X dflag = 1;
- X break;
- X case 'i':
- X offset = atof(&argv[i][2]);
- X if (offset < 0.0 || offset >= 8.5) {
- X fatal("bad indent");
- X /*NOTREACHED*/
- X }
- X break;
- X case 'l':
- X lflag = 1;
- X break;
- X case 'm':
- X mflag = 1;
- X break;
- X case 'o':
- X range = &argv[i][2];
- X if (checkrange(range)) {
- X fatal("bad range specification");
- X /*NOTREACHED*/
- X }
- X break;
- X case 'p':
- X pflag = 1;
- X propts = &argv[i][2];
- X break;
- X case 'P':
- X if (++i == argc) {
- X fatal("missing filename after -P");
- X /*NOTREACHED*/
- X }
- X prologue = argv[i];
- X break;
- X case 'r':
- X rflag = !rflag;
- X break;
- X case 's':
- X j = atoi(&argv[i][2]);
- X if ((p = get_psize(j)) == (struct psize *) NULL) {
- X fatal("bad point size");
- X /*NOTREACHED*/
- X }
- X break;
- X case 't':
- X tabstop = atoi(&argv[i][2]);
- X if (tabstop < 1) {
- X fatal("bad tabstop");
- X /*NOTREACHED*/
- X }
- X break;
- X case 'v':
- X vflag = 1;
- X break;
- X case 'S':
- X Sflag = 1;
- X break;
- X default:
- X (void) fprintf(stderr, "Usage: %s %s\n", progname, USAGE);
- X exit(1);
- X }
- X }
- X
- X /*
- X * Check that all files are readable
- X * This is so that no output at all is produced if any file is not
- X * readable in case the output is being piped to a printer
- X */
- X for (j = i; j < argc; j++) {
- X if (access(argv[j], R_OK) == -1) {
- X fatal("cannot access %s", argv[j]);
- X /*NOTREACHED*/
- X }
- X }
- X
- X point_size = p->size;
- X
- X if (lflag) {
- X start_y = LANDSCAPE_START_Y;
- X start_x = START_X + (int) (offset * 72.27);
- X lines_per_page = p->landscape_page_length;
- X columns = p->landscape_cols - (int) ceil(offset * p->charsperinch);
- X if (mflag) {
- X int nlines;
- X
- X nlines = (int) ceil((THREE_HOLE_Y * 72.27) / point_size);
- X start_y -= (nlines * point_size);
- X lines_per_page -= nlines;
- X columns -= (int) ceil(THREE_HOLE_Y * p->charsperinch);
- X }
- X }
- X else {
- X start_y = PORTRAIT_START_Y;
- X lines_per_page = p->portrait_page_length;
- X start_x = START_X;
- X if (mflag)
- X offset += THREE_HOLE_X;
- X start_x += (int) (offset * 72.27);
- X columns = p->portrait_cols - (int) ceil(offset * p->charsperinch);
- X }
- X if (vflag) {
- X (void) fprintf(stderr, "%s\n\n", version);
- X (void) fprintf(stderr, "Lines/page = %d\n", lines_per_page);
- X (void) fprintf(stderr, "Columns = %d\n", columns);
- X (void) fprintf(stderr, "X-offset = %5.2f inches\n", offset);
- X }
- X
- X setup();
- X preamble();
- X
- X first_file = i;
- X
- X if (!rflag && Sflag)
- X header(argc - first_file, argv + first_file);
- X
- X if (i == argc) { /* no files on command line */
- X infile = stdin;
- X if (pflag) {
- X build_prcmd(bufin, "");
- X if ((infile = popen(bufin, "r")) == (FILE *) NULL) {
- X fatal("popen failed");
- X /*NOTREACHED*/
- X }
- X }
- X if (vflag)
- X (void) fprintf(stderr, "printing stdin\n");
- X print(infile);
- X if (pflag)
- X (void) pclose(infile);
- X }
- X
- X /*
- X * If page reversal is performed, process the file arguments right to left,
- X * oth. left to right
- X * If the correct flag is used for the printer the first file argument
- X * will be on top in the printer's output tray when the paper is removed
- X */
- X if (rflag)
- X j = argc - 1;
- X else
- X j = i;
- X while (i < argc) {
- X infile = stdin;
- X if (pflag) {
- X build_prcmd(bufin, argv[j]);
- X if ((infile = popen(bufin, "r")) == (FILE *) NULL) {
- X fatal("popen failed");
- X /*NOTREACHED*/
- X }
- X }
- X else {
- X if (freopen(argv[j], "r", stdin) == (FILE *) NULL) {
- X fatal("can't open %s", argv[j]);
- X /*NOTREACHED*/
- X }
- X }
- X if (vflag)
- X (void) fprintf(stderr, "printing %s\n", argv[j]);
- X print(infile);
- X if (pflag)
- X (void) pclose(infile);
- X if (rflag)
- X j--;
- X else
- X j++;
- X i++;
- X }
- X
- X if (rflag && Sflag)
- X header(argc - first_file, argv + first_file);
- X
- X (void) printf("%%%%Trailer\n");
- X (void) printf("%%%%Pages: %d\n", page_count);
- X if (Sflag)
- X (void) putc(PS_EOF, stdout);
- X
- X if (fflush(stdout) == EOF) {
- X fatal("write error on stdout");
- X /*NOTREACHED*/
- X }
- X exit(0);
- X}
- X
- X/*
- X * Return a pointer to the point size structure for the
- X * specified point size
- X */
- struct psize *
- get_psize(size)
- int size;
- X{
- X register int i;
- X
- X for (i = 0; i < NPSIZES; i++)
- X if (psize[i].size == size)
- X break;
- X if (i == NPSIZES)
- X return((struct psize *) NULL);
- X return(&psize[i]);
- X}
- X
- X/*
- X * Initial lines sent to the LaserWriter
- X * This stuff is sent to stdout since we don't want it to be reversed
- X * Generates the PostScript header and includes the prologue file
- X * There is limited checking for I/O errors here
- X * When the standard prologue is being used we probably should verify
- X * that it is the correct version (via %%BeginProcSet)
- X */
- preamble()
- X{
- X FILE *fp;
- X
- X if ((fp = fopen(prologue, "r")) == (FILE *) NULL) {
- X fatal("can't open prologue file `%s'", prologue);
- X /*NOTREACHED*/
- X }
- X
- X if (Sflag)
- X (void) putc(PS_EOF, stdout);
- X
- X (void) printf("%%!PS-Adobe-2.0\n");
- X (void) printf("%%%%Creator: %s on %s\n", progname, hostname);
- X (void) printf("%%%%CreationDate: %s\n", currentdate);
- X (void) printf("%%%%For: %s\n", username);
- X (void) printf("%%%%DocumentFonts: %s", TEXTFONT);
- X if (Sflag)
- X (void) printf(" %s\n", HEADERFONT);
- X else
- X (void) printf("\n");
- X (void) printf("%%%%Pages: (atend)\n");
- X
- X while (fgets(bufin, sizeof(bufin), fp) != (char *) NULL)
- X fputs(bufin, stdout);
- X (void) fclose(fp);
- X if (ferror(stdout) || fflush(stdout) == EOF) {
- X fatal("write error on stdout");
- X /*NOTREACHED*/
- X }
- X}
- X
- X/*
- X * Generate a command, in the specified buffer, to print the given file
- X * according to the options in effect
- X */
- build_prcmd(buf, file)
- char *buf, *file;
- X{
- X
- X#ifdef SYSV
- X (void) sprintf(buf, "%s -e%d -w%d -l%d -s%c %s %s",
- X PR, tabstop, columns, lines_per_page, SEP_CHAR, propts, file);
- X#else
- X (void) sprintf(buf, "%s -w%d -l%d -s%c %s %s",
- X PR, columns, lines_per_page, SEP_CHAR, propts, file);
- X#endif
- X if (vflag)
- X (void) fprintf(stderr, "pr cmd: %s\n", buf);
- X}
- X
- X/*
- X * Print a file
- X *
- X * The input stream may be stdin, a file, or a pipe
- X * If page reversal is being performed, the output goes to a temporary file and
- X * then reverse() is called to do the page reversal to stdout
- X */
- print(infile)
- XFILE *infile;
- X{
- X register int eof, pagenum, r;
- X register char *p;
- X FILE *outfile;
- X char *mktemp();
- X
- X if (rflag) {
- X static char bigbuf[BUFOUT];
- X
- X page_map[0] = 0L;
- X (void) sprintf(bufin, "/tmp/%sXXXXXX", progname);
- X if (vflag)
- X (void) fprintf(stderr, "temp will be: %s ... ", bufin);
- X p = mktemp(bufin);
- X if (vflag)
- X (void) fprintf(stderr, "%s\n", p);
- X if ((outfile = fopen(p, "w+")) == (FILE *) NULL) {
- X (void) fprintf(stderr, "%s: can't create %s\n", progname, p);
- X cleanup();
- X /*NOTREACHED*/
- X }
- X setbuffer(outfile, bigbuf, sizeof(bigbuf));
- X if (!dflag)
- X (void) unlink(p);
- X else
- X (void) fprintf(stderr, "will not unlink %s\n", p);
- X }
- X else
- X outfile = stdout;
- X
- X pagenum = 1;
- X eof = 0;
- X while (!eof) {
- X row = start_y;
- X if ((r = inrange(pagenum, range)) == -1) {
- X cleanup();
- X /*NOTREACHED*/
- X }
- X else if (r == 1)
- X eof = printpage(infile, outfile);
- X else if (r == 0)
- X eof = flushpage(infile);
- X else {
- X fatal("bad inrange result");
- X /*NOTREACHED*/
- X }
- X pagenum++;
- X }
- X if (row != start_y)
- X endpage(outfile);
- X if (vflag)
- X (void) fprintf(stderr, "\n");
- X if (fflush(outfile) == EOF) {
- X fatal("write error while flushing output");
- X /*NOTREACHED*/
- X }
- X if (rflag) {
- X reverse(outfile);
- X (void) fclose(outfile);
- X }
- X}
- X
- X/*
- X * Process the next page
- X * Return 1 on EOF, 0 oth.
- X */
- printpage(infile, outfile)
- XFILE *infile, *outfile;
- X{
- X register int lineno;
- X
- X if (ungetc(getc(infile), infile) == EOF)
- X return(1);
- X
- X startpage(page_count + 1, outfile);
- X for (lineno = 0; lineno < lines_per_page; lineno++) {
- X if (fgetline(bufin, sizeof(bufin), infile) == (char *) NULL)
- X return(1);
- X if (bufin[0] == '\f')
- X break;
- X if (bufin[0] != '\0') {
- X (void) fprintf(outfile, "%d %d %s\n", start_x, row, MOVETO);
- X proc(bufin, outfile);
- X }
- X row -= point_size;
- X }
- X endpage(outfile);
- X return(0);
- X}
- X
- X/*
- X * The next page will not be printed; just consume the input and discard
- X * Don't change xrow since we don't want an endpage()
- X */
- flushpage(infile)
- XFILE *infile;
- X{
- X register int lineno, xrow;
- X
- X xrow = row;
- X for (lineno = 0; lineno < lines_per_page; lineno++) {
- X if (fgetline(bufin, sizeof(bufin), infile) == (char *) NULL)
- X return(1);
- X if (bufin[0] == '\f')
- X break;
- X xrow -= point_size;
- X }
- X return(0);
- X}
- X
- X/*
- X * Start a new page
- X */
- startpage(n, outfile)
- int n;
- XFILE *outfile;
- X{
- X
- X (void) fprintf(outfile, "%%%%Page: ? %d\n", n);
- X (void) fprintf(outfile, "%d /%s %s\n",
- X point_size, TEXTFONT, lflag ? STARTLPAGE : STARTPAGE);
- X}
- X
- X/*
- X * A page has been written to the temp file
- X * Record the start of the next page
- X * Terminate the page and indicate the start of the next
- X */
- endpage(outfile)
- XFILE *outfile;
- X{
- X long ftell();
- X
- X if (page_count == MAXPAGES) {
- X fatal("pagelimit (%d) reached", MAXPAGES);
- X /*NOTREACHED*/
- X }
- X (void) fprintf(outfile, "%d %s\n", ncopies, ENDPAGE);
- X if (rflag) {
- X if (fflush(outfile) == EOF) {
- X fatal("write error while flushing page");
- X /*NOTREACHED*/
- X }
- X page_map[++page_count] = ftell(outfile);
- X }
- X else
- X page_count++;
- X if (vflag)
- X (void) fprintf(stderr, "x");
- X}
- X
- X/*
- X * Print the pages to stdout in reverse order
- X * Assumes that the number of characters per page can be contained in an int
- X */
- reverse(outfile)
- XFILE *outfile;
- X{
- X register int i;
- X int bytecount, nbytes;
- X long lseek();
- X
- X if (vflag)
- X (void) fprintf(stderr, "\nreversing %d page%s\n", page_count,
- X page_count > 1 ? "s" : "");
- X if (dflag) {
- X for (i = 0; i <= page_count; i++)
- X (void) fprintf(stderr, "[%ld]\n", page_map[i]);
- X }
- X for (i = page_count - 1; i >= 0; i--) {
- X if (fseek(outfile, page_map[i], 0) == -1L) {
- X fatal("seek error");
- X /*NOTREACHED*/
- X }
- X nbytes = (int) (page_map[i + 1] - page_map[i]);
- X while (nbytes > 0) {
- X bytecount = min(nbytes, sizeof(bufout));
- X if (fread(bufout, 1, bytecount, outfile) != bytecount) {
- X fatal("read error while reversing pages");
- X /*NOTREACHED*/
- X }
- X if (fwrite(bufout, 1, bytecount, stdout) != bytecount) {
- X fatal("write error while reversing pages");
- X /*NOTREACHED*/
- X }
- X nbytes -= bytecount;
- X }
- X }
- X}
- X
- X/*
- X * Process a line of input, escaping characters when necessary and handling
- X * tabs
- X *
- X * The output is improved somewhat by coalescing consecutive tabs and
- X * backspaces and eliminating tabs at the end of a line
- X *
- X * Overprinting (presumably most often used in underlining) can be far from
- X * optimal; in particular the way nroff underlines by sequences like
- X * "_\ba_\bb_\bc" creates a large volume of PostScript. This isn't too
- X * serious since a lot of nroff underlining is unlikely.
- X *
- X * Since a newline is generated for each call there will be more
- X * newlines in the output than is necessary
- X */
- proc(in, outfile)
- char *in;
- XFILE *outfile;
- X{
- X register int i;
- X register char *last, *p, *q;
- X int currentp, instr, tabc, tabto;
- X char *savep;
- X static int colskip, ncols;
- X static int seen_sep = 0;
- X
- X currentp = 0;
- X instr = 0;
- X tabto = 0;
- X last = bufout + MAX_OUTPUT_LINE_LENGTH - 20; /* subtract slop factor */
- X
- X q = bufout;
- X *q = '\0';
- X for (p = in; *p != '\0'; p++) {
- X switch (*p) {
- X case SEP_CHAR:
- X /*
- X * This assumes that the input buffer contains the entire line
- X * oth. the column count will be off
- X * Also, the input stream must be formatted into a constant number
- X * of columns oth. it would be necessary to scan each line to
- X * count SEP_CHARs (which is not hard but could be slow)
- X */
- X if (!seen_sep) { /* discern number of columns */
- X seen_sep = 1;
- X ncols = 2; /* there are at least two columns... */
- X savep = p++;
- X while (*p != '\0') {
- X if (*p++ == SEP_CHAR)
- X ncols++;
- X }
- X p = savep;
- X colskip = columns / ncols;
- X if (vflag)
- X (void) fprintf(stderr, "Using %d columns\n", ncols);
- X }
- X if (instr) {
- X (void) sprintf(q, ")%s ", SHOW);
- X q += strlen(q);
- X instr = 0;
- X }
- X tabto += (colskip - currentp);
- X currentp = 0;
- X break;
- X case '\t':
- X /*
- X * Count the number of tabs that immediately follow the one we're
- X * looking at
- X */
- X tabc = 0;
- X while (*(p + 1) == '\t') {
- X p++;
- X tabc++;
- X }
- X if (currentp > 0) { /* not beginning of line */
- X i = tabstop - (currentp % tabstop) + tabc * tabstop;
- X if (instr) {
- X (void) sprintf(q, ")%s ", SHOW);
- X q += strlen(q);
- X instr = 0;
- X }
- X }
- X else
- X i = (tabc + 1) * tabstop;
- X tabto += i;
- X currentp += i;
- X break;
- X case '\b':
- X *q = '\0';
- X (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- X /* backspacing over tabs doesn't work... */
- X if (tabto != 0) {
- X fatal("attempt to backspace over a tab");
- X /*NOTREACHED*/
- X }
- X p++;
- X for (i = 1; *p == '\b'; p++)
- X i++;
- X if (currentp - i < 0) {
- X fatal("too many backspaces");
- X /*NOTREACHED*/
- X }
- X if (!instr) {
- X fatal("bad backspacing");
- X /*NOTREACHED*/
- X }
- X if (i == 1) /* frequent case gets special attention */
- X (void) sprintf(bufout, "%s (", BACKSPACE);
- X else
- X (void) sprintf(bufout, "-%d %s (", i, TAB);
- X currentp -= i;
- X q = bufout + strlen(bufout);
- X p--;
- X break;
- X case '\f':
- X tabto = 0; /* optimizes */
- X *q = '\0';
- X if (instr)
- X (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- X else
- X (void) fprintf(outfile, "%s\n", bufout);
- X endpage(outfile);
- X startpage(page_count + 1, outfile);
- X row = start_y;
- X (void) fprintf(outfile, "%d %d %s\n", start_x, row, MOVETO);
- X q = bufout;
- X currentp = 0;
- X instr = 0;
- X break;
- X case '\r':
- X tabto = 0; /* optimizes */
- X if (instr) {
- X *q = '\0';
- X (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- X instr = 0;
- X q = bufout;
- X }
- X (void) fprintf(outfile, "%d %d %s\n", start_x, row, MOVETO);
- X currentp = 0;
- X break;
- X case '\\':
- X case '(':
- X case ')':
- X if (!instr) {
- X if (tabto) {
- X (void) sprintf(q, "%d %s ", tabto, TAB);
- X q += strlen(q);
- X tabto = 0;
- X }
- X *q++ = '(';
- X instr = 1;
- X }
- X *q++ = '\\';
- X *q++ = *p;
- X currentp++;
- X break;
- X default:
- X /*
- X * According to the PostScript Language Manual, PostScript files
- X * can contain only "the printable subset of the ASCII character
- X * set (plus the newline marker)".
- X */
- X if (!isascii(*p) || !isprint(*p)) {
- X fatal("bad character in input");
- X /*NOTREACHED*/
- X }
- X if (!instr) {
- X if (tabto) {
- X (void) sprintf(q, "%d %s ", tabto, TAB);
- X q += strlen(q);
- X tabto = 0;
- X }
- X *q++ = '(';
- X instr = 1;
- X }
- X *q++ = *p;
- X currentp++;
- X break;
- X }
- X if (q >= last) {
- X *q = '\0';
- X if (instr)
- X (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- X else
- X (void) fprintf(outfile, "%s\n", bufout);
- X q = bufout;
- X instr = 0;
- X }
- X }
- X if (instr) {
- X (void) sprintf(q, ")%s", SHOW);
- X q += strlen(q);
- X }
- X else
- X *q = '\0';
- X if (q >= last) {
- X fatal("bufout overflow");
- X /*NOTREACHED*/
- X }
- X if (bufout[0] != '\0')
- X (void) fprintf(outfile, "%s\n", bufout);
- X}
- X
- X/*
- X * Find out who the user is, etc.
- X * Possible system dependencies here...
- X */
- setup()
- X{
- X int len;
- X char *p;
- X long t, time();
- X int gethostname();
- X char *ctime(), *getlogin(), *malloc();
- X struct passwd *pw, *getpwuid();
- X
- X if ((p = getlogin()) == (char *) NULL) {
- X if ((pw = getpwuid(getuid())) == (struct passwd *) NULL)
- X p = "Whoknows";
- X else
- X p = pw->pw_name;
- X endpwent();
- X }
- X username = (char *) malloc((unsigned) (strlen(p) + 1));
- X (void) strcpy(username, p);
- X
- X#ifdef HOSTNAME
- X (void) strncpy(hostname, HOSTNAME, sizeof(hostname));
- X hostname[sizeof(hostname) - 1] = '\0';
- X#else
- X (void) gethostname(hostname, sizeof(hostname));
- X#endif
- X
- X t = time((long *) 0);
- X p = ctime(&t);
- X len = strlen(p);
- X *(p + len - 1) = '\0'; /* zap the newline character */
- X currentdate = (char *) malloc((unsigned) len);
- X (void) strcpy(currentdate, p);
- X}
- X
- X/*
- X * Print a header page
- X * Assumes setup() has already been called to fill in the user, host, etc.
- X * Uses HEADERFONT in HEADERPS point
- X */
- header(nfiles, files)
- int nfiles;
- char **files;
- X{
- X register int i;
- X register char *p;
- X
- X if (vflag) {
- X (void) fprintf(stderr, "printing header\n");
- X (void) fprintf(stderr, "%d file%s are:\n", nfiles,
- X nfiles > 1 ? "s" : "");
- X if (nfiles == 0)
- X (void) fprintf(stderr, "\tstdin\n");
- X for (i = 0; i < nfiles; i++)
- X (void) fprintf(stderr, "\t%s\n", files[i]);
- X }
- X
- X (void) fprintf(stdout, "%%%%Page: ? %d\n", ++page_count);
- X (void) fprintf(stdout, "%d /%s %s\n", HEADERPS, HEADERFONT, STARTHPAGE);
- X
- X /*
- X * The header sheet looks like:
- X *
- X * ----------------------------
- X * ----------------------------
- X *
- X * User:
- X * Host:
- X * Date:
- X * Files:
- X *
- X * ----------------------------
- X * ----------------------------
- X */
- X row = START_Y_HEADER;
- X (void) printf("%s %d %d %s\n", NEWPATH, START_X, row, MOVETO);
- X (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- X row -= 6;
- X (void) printf("%d %d %s\n", START_X, row, MOVETO);
- X (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- X row -= 24;
- X (void) printf("%s\n", STROKE);
- X
- X (void) printf("%d %d %s\n", START_X, row, MOVETO);
- X (void) sprintf(bufin, "User: %s", username);
- X proc(bufin, stdout);
- X row -= 24;
- X (void) printf("%d %d %s\n", START_X, row, MOVETO);
- X (void) sprintf(bufin, "Host: %s", hostname);
- X proc(bufin, stdout);
- X row -= 24;
- X (void) printf("%d %d %s\n", START_X, row, MOVETO);
- X (void) sprintf(bufin, "Date: %s", currentdate);
- X proc(bufin, stdout);
- X row -= 24;
- X
- X if (nfiles == 0) {
- X (void) printf("%d %d %s\n", START_X, row, MOVETO);
- X (void) sprintf(bufin, "File: <stdin>");
- X proc(bufin, stdout);
- X }
- X else {
- X register int len, max, sum;
- X
- X /*
- X * If the list of files is "too long" we'll only print as many as
- X * possible
- X * Arbitrary chop off point is 50 characters
- X * (assume bufin is bigger than this)
- X */
- X (void) printf("%d %d %s\n", START_X, row, MOVETO);
- X (void) sprintf(bufin, "File%s: ", nfiles > 1 ? "s" : "");
- X p = bufin + (sum = strlen(bufin));
- X max = 50;
- X for (i = 0; i < nfiles - 1; i++) {
- X sum += (len = strlen(files[i]) + 1);
- X if (sum >= max)
- X break;
- X (void) sprintf(p, "%s,", files[i]);
- X p += len;
- X }
- X sum += (len = strlen(files[i]) + 1);
- X if (sum < max)
- X (void) sprintf(p, "%s", files[i]);
- X else
- X (void) strcpy(p, "...");
- X proc(bufin, stdout);
- X }
- X
- X row -= 12;
- X (void) printf("%s %d %d %s\n", NEWPATH, START_X, row, MOVETO);
- X (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- X row -= 6;
- X (void) printf("%d %d %s\n", START_X, row, MOVETO);
- X (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- X (void) printf("%s\n", STROKE);
- X (void) printf("1 %s\n", ENDPAGE);
- X if (fflush(stdout) == EOF) {
- X fatal("write error on stdout");
- X /*NOTREACHED*/
- X }
- X}
- X
- X/*
- X * Special version of fgets
- X * Read until a formfeed, newline, or overflow
- X * If a formfeed is the first character, return it immediately
- X * If a formfeed is found after the first character, replace it by a newline
- X * and push the formfeed back onto the input stream
- X * A special case is a formfeed followed by a newline in which case the
- X * newline is ignored
- X * The input buffer will be null-terminated and will *not* end with a newline
- X * The buffer size n includes the null
- X */
- char *
- fgetline(s, n, iop)
- char *s;
- int n;
- register FILE *iop;
- X{
- X register int ch;
- X register char *cs;
- X
- X if (n < 2) {
- X fatal("fgetline called with bad buffer size!?");
- X /*NOTREACHED*/
- X }
- X
- X cs = s;
- X n--; /* the null */
- X
- X /*
- X * Check out the special cases
- X */
- X if ((ch = getc(iop)) == EOF)
- X return((char *) NULL);
- X if (ch == '\f') {
- X#ifdef PRBUG
- X if (pflag) {
- X /*
- X * Filter out the formfeeds
- X */
- X do {
- X if (ch == '\f')
- X continue;
- X if (ch == '\n')
- X break;
- X *cs++ = ch;
- X n--;
- X } while (n > 0 && (ch = getc(iop)) != EOF);
- X if (ch == EOF) {
- X if (ungetc(ch, iop) == EOF && !feof(iop)) {
- X /* Shouldn't happen since a getc() was just done */
- X fatal("fgetline - ungetc failed");
- X /*NOTREACHED*/
- X }
- X }
- X else if (ch != '\n') {
- X fatal("fgetline - input line too long");
- X /*NOTREACHED*/
- X }
- X *cs = '\0';
- X return(s);
- X }
- X#endif
- X if ((ch = getc(iop)) != '\n') {
- X /*
- X * If EOF was just read it will be noticed next time through
- X */
- X if (ungetc(ch, iop) == EOF && !feof(iop)) {
- X /* Shouldn't happen since a getc() was just done */
- X fatal("fgetline - ungetc failed");
- X /*NOTREACHED*/
- X }
- X }
- X *cs++ = '\f';
- X *cs = '\0';
- X return(s);
- X }
- X
- X /*
- X * Check for "weird" input characters is made in proc()
- X */
- X while (n-- > 0) {
- X if (ch == '\f' || ch == '\n')
- X break;
- X *cs++ = ch;
- X if ((ch = getc(iop)) == EOF)
- X break;
- X }
- X
- X if (ch == EOF && cs == s) /* Nothing was read */
- X return((char *) NULL);
- X if (ch == '\f') {
- X if (ungetc(ch, iop) == EOF)
- X (void) fprintf(stderr, "fgetline - can't ungetc??\n");
- X }
- X else if (ch != '\n' && ch != EOF) {
- X fatal("fgetline - input line too long");
- X /*NOTREACHED*/
- X }
- X *cs = '\0';
- X return(s);
- X}
- X
- X/*VARARGS*/
- fatal(s, a, b, c, d, e, f, g, h, i, j)
- char *s;
- X{
- X
- X (void) fprintf(stderr, "%s: ", progname);
- X (void) fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j);
- X (void) fprintf(stderr, "\n");
- X cleanup();
- X /*NOTREACHED*/
- X}
- X
- X/*
- X * Clean up and exit after an error
- X */
- cleanup()
- X{
- X
- X exit(1);
- X}
- X
- END_OF_FILE
- if test 26651 -ne `wc -c <'lwf.c'`; then
- echo shar: \"'lwf.c'\" unpacked with wrong size!
- fi
- # end of 'lwf.c'
- fi
- if test -f 'lwf.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lwf.man'\"
- else
- echo shar: Extracting \"'lwf.man'\" \(6229 characters\)
- sed "s/^X//" >'lwf.man' <<'END_OF_FILE'
- X.TH LWF 1-LOCAL "21 February 1988"
- X.UC
- X.SH NAME
- lwf \- ASCII to PostScript filter
- X.SH SYNOPSIS
- X.B lwf
- X[-c#] [-d] [-i#] [-l] [-m] [-olist] [-p[str]]
- X.br
- X.ti +4
- X[-P filename] [-r] [-s#] [-S] [-t#] [-v] [file ...]
- X.SH DESCRIPTION
- X.I Lwf
- takes one or more ASCII text files as input and produces PostScript
- instructions that may be sent (see \fBlpr(1)\fR) to a PostScript printer
- X(e.g., an Apple LaserWriter) for printing.
- If no files are given on the command line, the standard input is read.
- The program correctly handles the form feed character and tabs and
- understands backspacing; underscores followed by backspaces
- may be used to underline.
- Courier font is used.
- The output conforms to the Adobe 2.0 file structuring conventions.
- X.PP
- Note that flag arguments apply to all of the files in the argument list.
- XFor example, using ``-s8'' prints each of the files in 8 point type.
- X.PP
- Multiple copies of each page can be printed by immediately following the
- X.B -c
- flag with the number of copies to make.
- The pages are not collated.
- X.PP
- Lines may be indented (shifted to the right) using the \fB-i\fR flag.
- This flag is immediately followed by the distance in inches to shift
- all text from the left edge of the paper instead of the default amount
- X(about 1/3 of an inch); the resolution is approximately 1/72 of an inch.
- X.PP
- The
- X.B -l
- flag indicates that landscape format is to be used instead of the default
- portrait format.
- X.PP
- Margins suitable for use with a three hole punch can be obtained using the
- X.B -m
- flag.
- This flag may be used with either portrait or landscape mode.
- In portrait mode the
- X.B -m
- flag and any indentation specified by a
- X.B -i
- flag are additive.
- X.PP
- The
- X.B -o
- flag is immediately followed by a range specification that indicates
- which pages are to be printed.
- A range specification is a comma-separated list of numbers and ranges.
- A number N selects the Nth page;
- a range N:M selects the Nth through Mth pages, inclusive;
- an initial :N selects from the beginning up to and including the
- Nth page; and a final N: selects from the Nth page to the end.
- The default, ``:'', is to print all pages.
- X.PP
- The
- X.B -p
- flag indicates that
- X.B pr(1)
- is to be used to perform pagination and print page headers.
- An argument string to be passed on to \fBpr(1)\fR can immediately
- follow the flag.
- The usual way of producing multicolumn output is to pass a
- X.B -n
- flag to
- X\fBpr(1)\fR, where
- X.B n
- is the number of columns to generate.
- Note that this string must be properly quoted if it contains whitespace,
- metacharacters, backslashes, etc.
- X\fILwf\fR passes on the number of lines and columns to
- X\fBpr(1)\fR so that multicolumn output is handled correctly.
- When specifying multicolumns you are responsible for selecting
- an appropriate point size and/or landscape format.
- The formfeed character is handled incorrectly by some versions of
- X\fBpr(1)\fR when multiple columns have been specified.
- Instead of starting a new column or page it simply passes formfeeds
- through.
- X.B Lwf
- filters out these formfeeds.
- X.PP
- X.I Lwf
- normally includes a standard PostScript prologue in its output
- X(usually /usr/local/lib/lwf.prologue).
- The argument following a
- X.B -P
- flag specifies a prologue file to be substituted for the standard
- system file.
- X.PP
- The default is to not perform page reversal, which is correct for printers
- like the NEC Silentwriter LC-890.
- The
- X.B -r
- flag enables page reversal so that the pages appear in
- the correct sequence in the output tray of printers like the Apple
- LaserWriter.
- X.PP
- The
- X.B -s
- flag, immediately followed by a 7, 8, 9, 10, 11, or 12 causes
- the corresponding point size to be used.
- The default point size is 10.
- X.PP
- By default, the output of
- X.I lwf
- is intended to go through a spooler that monitors the status of the
- printer and separates jobs.
- The
- X.B -S
- flag indicates that such a monitor is not being used and that a
- header page should be printed to separate jobs and end-of-file characters
- should be inserted in the output.
- X.PP
- The
- X.B -t
- flag is immediately followed by a number indicating the distance between
- tab stops.
- The default value is 8 characters.
- X.PP
- The
- X.B -d
- and
- X.B -v
- flags are used for debugging.
- X.SH EXAMPLES
- The command
- X.sp 2
- X.ti +5
- lwf -p-2 -i0.5 -s12 file1.c file2.c | lpr -Plw
- X.sp 2
- would print the two files on printer 'lw' in portrait format with
- page headings, indenting 0.5 inches from the left edge, using 12
- point type.
- Each file would be printed in two columns.
- X.sp 1
- The command
- X.sp 2
- X.ti +5
- lwf -l -s7 -p'-h foo' | lpr -Plw
- X.sp 2
- would print the standard input with page headings in landscape format
- using 7 point type.
- The filename for the header line would be 'foo'.
- X.sp 1
- The command
- X.sp 2
- X.ti +5
- lwf -p'-h foo .login -h bar .cshrc' | lpr -Plw
- X.sp 2
- would print the file ``.login'' with a header title ``foo'' and ``.cshrc''
- with the header title ``bar''.
- X.sp 1
- A useful csh alias is:
- X.sp 2
- X.ti +5
- alias prlw 'lwf -s7 -t4 -l -p-2 \\!* | lpr -Plw'
- X.sp 2
- which, when invoked as
- X.sp 2
- X.ti +5
- prlw foo1 foo2
- X.sp 2
- prints foo1 and foo2, two columns per page, on printer 'lw'.
- X.SH FILES
- X/tmp/lwfXXXXXX \- temporary file used for page reversal
- X.SH SEE ALSO
- pr(1), lpr(1)
- X.SH LIMITATIONS
- The maximum input line length is 1024 characters.
- This should not present a problem since the corresponding output line
- length would be too long to be printed.
- The program quits and prints a message if an input line is too long.
- Output lines that are too long are normally silently truncated by the
- printer.
- X.sp 2
- X.I Lwf
- can be compiled such that there is a limit on the number of pages it can
- produce.
- X.SH BUGS
- It might be argued that flags should be allowed to be interspersed between
- file arguments.
- X.sp 2
- The character '\\001' (SOH) should not appear in the input as it is used
- within the program to delimit columns.
- The first time the program reads this character it determines the number
- of columns being printed; all subsequent lines are expected to
- have this number of columns or be ``single column''.
- X.sp 2
- A \fB-s\fR flag should not be passed on to \fBpr(1)\fR since
- X.I lwf
- uses it.
- X.sp 2
- The program can only handle the 6 different point sizes and the single
- font.
- X.sp 2
- So much for metric.
- X.SH AUTHOR
- Barry Brachman
- X.br
- Dept. of Computer Science
- X.br
- University of British Columbia
- X
- END_OF_FILE
- if test 6229 -ne `wc -c <'lwf.man'`; then
- echo shar: \"'lwf.man'\" unpacked with wrong size!
- fi
- # end of 'lwf.man'
- fi
- if test -f 'prologue' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'prologue'\"
- else
- echo shar: Extracting \"'prologue'\" \(565 characters\)
- sed "s/^X//" >'prologue' <<'END_OF_FILE'
- X%%EndComments
- X% PostScript Prologue for lwf V2.0 ASCII to PostScript filter
- X% Barry Brachman
- X% Dept. of Computer Science
- X% University of British Columbia
- X/B {NW 0 rmoveto}bind def
- X/EP {SV restore /#copies exch def showpage}bind def
- X/L /lineto load def
- X/M /moveto load def
- X/NP /newpath load def
- X/S /show load def
- X/SHP {SP 2 setlinewidth}bind def
- X/SLP {SP 612 0 translate 90 rotate}bind def
- X/SP {/SV save def findfont exch scalefont setfont ( )
- X stringwidth pop dup /W exch def neg /NW exch def}bind def
- X/ST /stroke load def
- X/T {W mul 0 rmoveto}bind def
- X%%EndProlog
- END_OF_FILE
- if test 565 -ne `wc -c <'prologue'`; then
- echo shar: \"'prologue'\" unpacked with wrong size!
- fi
- # end of 'prologue'
- fi
- if test -f 'range.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'range.c'\"
- else
- echo shar: Extracting \"'range.c'\" \(7832 characters\)
- sed "s/^X//" >'range.c' <<'END_OF_FILE'
- X/* vi: set tabstop=4 : */
- X
- X/*
- X * Return 1 if the given number is in the specified range,
- X * -1 if there is an error in the range specification,
- X * 0 otherwise
- X *
- X * Ranges have a similar (we use a colon instead of a dash) form to that
- X * used by [nt]roff; i.e., a comma separated list of specifiers of the
- X * form:
- X * 1) n means x such that x = n
- X * 2) :n means all x such that x <= n
- X * 3) n: means all x such that x >= n
- X * 4) n:m means all x such that n <= x <= m
- X * 5) : means all x
- X * n is an int
- X *
- X * Problems:
- X * The routine prints an error message if the range is strange - this
- X * might not always be desirable.
- X *
- X * Jul/86 BJB
- X */
- X
- X/*
- X * ===================================================================
- X *
- X * Permission is given to freely copy and distribute this software
- X * providing:
- X *
- X * 1) You do not sell it,
- X * 2) You do not use it for commercial advantage, and
- X * 3) This notice accompanies the distribution
- X *
- X * Copyright (c) 1988
- X * Barry Brachman
- X * Dept. of Computer Science
- X * Univ. of British Columbia
- X * Vancouver, B.C. V6T 1W5
- X *
- X * .. {ihnp4!alberta, uw-beaver, uunet}!ubc-vision!ubc-csgrads!brachman
- X * brachman@grads.cs.ubc.cdn
- X * brachman%ubc.csnet@csnet-relay.arpa
- X * brachman@ubc.csnet
- X * ====================================================================
- X */
- X
- X#include <ctype.h>
- X#include <stdio.h>
- X
- X#define streq(a, b) (!strcmp((a), (b)))
- X#define smalloc(a, t, s) ((a = (t) malloc((unsigned) (s))) == NULL)
- X#define srealloc(a, t, b, s) ((a = (t) realloc(b, (unsigned) (s))) == NULL)
- X#define max(a, b) ((a) >= (b) ? (a) : (b))
- X
- X#define SEP_CHAR ':'
- X#define SEP_T 0 /* separator token */
- X#define NUM_T 1 /* number token */
- X#define BAD_T 2 /* token for bad character */
- X
- X#define STR_ALLOC 80
- X
- struct range_header {
- X char *range_str; /* range character string */
- X int range_str_alloc; /* length in bytes */
- X int nranges; /* number of range entries */
- X struct range *range;
- X} range_header = {
- X NULL, 0, NULL
- X};
- X
- X/*
- X * If hflag (lflag) is non-zero then the high (low) value is present
- X */
- struct range {
- X char hflag; /* high value present */
- X char lflag; /* low value present */
- X int high; /* high part of range */
- X int low; /* low part of range */
- X};
- X
- X#ifdef RANGE_DEBUG
- X
- X/*
- X * This is a program for demonstrating and debugging the range checking
- X * code
- X * Enter a range when prompted
- X * (If there is a previous range shown you may enter <return> to
- X * reselect it)
- X * Enter a value
- X * The program will indicate whether the value is in the given range
- X */
- X
- char buf[BUFSIZ], range[BUFSIZ];
- X
- main(argc, argv)
- int argc;
- char **argv;
- X{
- X register int i;
- X char *p;
- X struct range_header *rh;
- X struct range *r;
- X FILE *fp;
- X char *gets(), *index(), *strcpy();
- X
- X buf[0] = range[0] = '\0';
- X if (argc == 2) {
- X if ((fp = fopen(argv[1], "r")) == NULL) {
- X (void) fprintf(stderr, "Can't open %s\n", argv[1]);
- X exit(1);
- X /*NOTREACHED*/
- X }
- X }
- X else
- X fp = stdin;
- X
- X if (fp == stdin)
- X (void) printf("Range? ");
- X while (fgets(buf, sizeof(buf), fp) != NULL) {
- X if ((p = index(buf, '\n')) != NULL)
- X *p = '\0';
- X if (buf[0] != '\0') {
- X (void) strcpy(range, buf);
- X if (checkrange(range)) {
- X if (fp == stdin)
- X (void) printf("Range? ");
- X continue;
- X }
- X rh = &range_header;
- X (void) printf("%s (%d alloc) (%d ranges):\n",
- X rh->range_str, rh->range_str_alloc, rh->nranges);
- X for (r = rh->range, i = 0; i < rh->nranges; i++, r++)
- X (void) printf("hflag=%d lflag=%d high=%d low=%d\n",
- X r->hflag, r->lflag, r->high, r->low);
- X }
- X if (fp != stdin)
- X continue;
- X (void) printf("Value? ");
- X if (gets(buf) == NULL)
- X break;
- X i = inrange(atoi(buf), range);
- X if (i == 0)
- X (void) printf("\tno\n");
- X else if (i == 1)
- X (void) printf("\tyes\n");
- X else if (i == -1)
- X (void) printf("\terror\n");
- X else
- X (void) printf("\tbad result\n");
- X (void) printf("Range ['%s']? ", range);
- X }
- X (void) printf("\n");
- X}
- X#endif RANGE_DEBUG
- X
- X/*
- X * Check and compile the given range specification and then determine if
- X * the number is in the range
- X * Return -1 if there is a compilation error, 1 if the number is in the
- X * range, or 0 if the number isn't in the range
- X */
- inrange(num, range_spec)
- int num;
- char *range_spec;
- X{
- X register int i, rc;
- X register struct range_header *rh;
- X register struct range *r;
- X
- X if (checkrange(range_spec))
- X return(-1);
- X rh = &range_header;
- X rc = 0;
- X for (r = rh->range, i = 0; rc == 0 && i < rh->nranges; i++, r++) {
- X if (r->hflag) {
- X if (num > r->high)
- X continue;
- X if (r->lflag && num < r->low)
- X continue;
- X rc = 1;
- X }
- X else if (r->lflag) {
- X if (num >= r->low)
- X rc = 1;
- X }
- X else /* both unset -> ":" */
- X rc = 1;
- X }
- X return(rc);
- X}
- X
- X/*
- X * Check and compile a range specification
- X * Print a message and return -1 on error; return 0 oth.
- X *
- X * Could be more efficient by allocating more structures at a time... SMOP
- X */
- checkrange(range_spec)
- char *range_spec;
- X{
- X register struct range_header *rh;
- X register struct range *r;
- X int len;
- X int ltype, lval, rtype, rval;
- X char *p;
- X char *malloc(), *realloc(), *strcpy();
- X
- X rh = &range_header;
- X /*
- X * Check if the previous range is being used
- X */
- X if (rh->range_str != NULL && streq(range_spec, rh->range_str))
- X return(0);
- X
- X /*
- X * New range spec
- X * If there is enough space, reuse it; oth. allocate enough
- X * (amount allocated never shrinks)
- X */
- X len = max(strlen(range_spec) + 1, STR_ALLOC);
- X if (rh->range_str != NULL && len > rh->range_str_alloc) {
- X free(rh->range_str);
- X rh->range_str = (char *) malloc((unsigned) len);
- X rh->range_str_alloc = len;
- X }
- X else if (rh->range_str == NULL) {
- X rh->range_str = (char *) malloc((unsigned) len);
- X rh->range_str_alloc = len;
- X }
- X (void) strcpy(rh->range_str, range_spec);
- X if (rh->range != NULL)
- X free((char *) rh->range);
- X rh->range = NULL;
- X
- X p = range_spec;
- X while (1) {
- X lval = getnum(&p, <ype);
- X if (ltype == BAD_T) {
- X (void) fprintf(stderr, "range: bad first number\n");
- X *rh->range_str = '\0'; /* invalidate */
- X return(-1);
- X }
- X
- X if (rh->range == NULL) {
- X smalloc(r, struct range *, sizeof(struct range));
- X rh->nranges = 1;
- X }
- X else {
- X len = sizeof(struct range) * ++(rh->nranges);
- X srealloc(r, struct range *, (char *) rh->range, len);
- X }
- X rh->range = r;
- X r += rh->nranges - 1; /* point to new one */
- X r->hflag = r->lflag = 0;
- X r->high = r->low = 0;
- X
- X /*
- X * If ltype != NUM_T there is no lval
- X */
- X if (ltype == NUM_T) {
- X r->lflag = 1;
- X r->low = lval;
- X }
- X
- X switch (*p) {
- X case ',': /* single number */
- X r->hflag = 1;
- X r->high = lval;
- X p++;
- X continue;
- X
- X case '\0': /* single number at end */
- X r->hflag = 1;
- X r->high = lval;
- X return(0);
- X
- X case ':':
- X p++;
- X if (*p == '\0') /* no rval */
- X return(0);
- X if (*p == ',') { /* no rval */
- X p++;
- X break;
- X }
- X
- X rval = getnum(&p, &rtype);
- X if (rtype == BAD_T) {
- X (void) fprintf(stderr, "range: bad second number\n");
- X *rh->range_str = '\0';
- X return(-1);
- X }
- X
- X if (lval > rval) {
- X (void) fprintf(stderr, "range: values reversed\n");
- X *rh->range_str = '\0'; /* invalidate */
- X return(-1);
- X }
- X r->hflag = 1;
- X r->high = rval;
- X if (*p == '\0')
- X return(0);
- X if (*p == ',')
- X p++;
- X break;
- X
- X default:
- X (void) fprintf(stderr, "range: bad character\n");
- X *rh->range_str = '\0'; /* invalidate */
- X return(-1);
- X }
- X }
- X}
- X
- static
- getnum(pp, type)
- char **pp;
- int *type;
- X{
- X register int sign, val;
- X register char *p;
- X
- X p = *pp;
- X if (!isdigit(*p) && *p != '-') {
- X if (*p == SEP_CHAR)
- X *type = SEP_T;
- X else
- X *type = BAD_T;
- X return(0);
- X }
- X sign = 1;
- X if (*p == '-') {
- X sign = -1;
- X p++;
- X }
- X if (!isdigit(*p)) {
- X *type = BAD_T;
- X return(0);
- X }
- X for (val = 0; isdigit(*p) && *p != '\0'; p++)
- X val = val * 10 + *p - '0';
- X if (*p != '\0' && *p != ',' && *p != SEP_CHAR) {
- X *type = BAD_T;
- X return(0);
- X }
- X *pp = p;
- X *type = NUM_T;
- X return(sign * val);
- X}
- X
- END_OF_FILE
- if test 7832 -ne `wc -c <'range.c'`; then
- echo shar: \"'range.c'\" unpacked with wrong size!
- fi
- # end of 'range.c'
- fi
- echo shar: End of shell archive.
- exit 0
-